package com.example.recordhelper.common;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.boot.logging.LogLevel;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.TimeUnit;

/**
 * @Author: zhouyuehan
 * @Date: 2024/10/25 16:27
 */
@Slf4j
public class FFmpegForwardAndRecordProcess {

    private final Long id;
    private final Process process;
    private Thread outputThread;
    private Thread errorThread;

    public FFmpegForwardAndRecordProcess(Long id, String input, String sourceId, String forwardUrl) {
        String dirPath = "E:\\record\\" + sourceId;
        String fileName = sourceId + "_%Y-%m-%d_%H-%M-%S";
        if (input.contains("rtmp:")) {
            fileName += ".flv";
        } else if (input.contains(".m3u8")) {
            fileName += ".mp4";
        } else {
            throw new IllegalArgumentException("无法识别的输入协议");
        }
        this.id = id;
        File dir = new File(dirPath);
        if (!dir.exists()) {
            dir.mkdirs();
        }
        ProcessBuilder pb;
        if (StringUtils.isBlank(forwardUrl)) {
            pb = new ProcessBuilder().directory(dir).command("E:\\ffmpeg-master-latest-win64-gpl\\bin\\ffmpeg", "-i", input, "-c:v", "copy", "-c:a", "copy", "-f", "segment", "-segment_time", "1200", "-reset_timestamps", "1", "-strftime", "1", String.format("%s", fileName));
        } else {
            throw new IllegalArgumentException("");
//            pb = new ProcessBuilder().directory(dir).command("E:\\ffmpeg-master-latest-win64-gpl\\bin\\ffmpeg", "-i", input, "-c:v", "copy", "-c:a", "copy", "-f", "segment", "-segment_time", "900", "-f", "tee", "-map", "0:v", "-map", "0:a", "-strftime", "1", String.format("%s|[f=flv]%s", fileName, forwardUrl));
        }
        log.info("执行命令：{}", String.join(" ", pb.command()));
        try {
            process = pb.start();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        outputThread = initIOStreamThread(process.getInputStream(), LogLevel.INFO);
        errorThread = initIOStreamThread(process.getErrorStream(), LogLevel.INFO);
        outputThread.start();
        errorThread.start();
    }

    private Thread initIOStreamThread(InputStream stream, LogLevel logLevel) {
        return new Thread(() -> {
            try (BufferedReader reader = new BufferedReader(new InputStreamReader(stream))) {
                String line;
                while ((line = reader.readLine()) != null) {
                    if (line.startsWith("frame=")) {
                        continue;
                    }
                    if (LogLevel.ERROR.equals(logLevel)) {
                        log.error("[id={},pid={}] ffmpeg error: {}", id, process.pid(), line);
                    } else {
                        log.info("[id={},pid={}] ffmpeg ouput: {}", id, process.pid(), line);
                    }
                }
            } catch (IOException e) {
                log.error("[id={},pid={}] 读取输出流失败: ", id, process.pid(), e);
            }
        });
    }

    public int waitFor() throws InterruptedException {
        outputThread.join();
        errorThread.join();
        return process.waitFor();
    }

    public void destroy() {
        try {
            process.getOutputStream().write("q".getBytes(StandardCharsets.UTF_8));
            process.getOutputStream().flush();
            process.waitFor(10, TimeUnit.SECONDS);
            outputThread.interrupt();
            errorThread.interrupt();
            log.info("[id={},pid={}] ffmpeg进程正常退出", id, process.pid());
        } catch (IOException | InterruptedException e) {
            throw new RuntimeException(e);
        } finally {
            process.destroy();
            log.info("[id={},pid={}] ffmpeg进程已销毁", id, process.pid());
        }
    }

    public Long getId() {
        return id;
    }

    public String getPid() {
        return String.valueOf(process.pid());
    }
}
